package com.example.myproject.service.impl;
import com.example.myproject.dto.torrent.DownloadRecordDTO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dampcake.bencode.BencodeException;
import com.example.myproject.dto.*;
import com.example.myproject.dto.torrent.*;
import com.example.myproject.exception.BusinessException;
import com.example.myproject.mapper.*;
import com.example.myproject.model.DownloadRecord;
import com.example.myproject.model.Torrent;
import com.example.myproject.model.TorrentTag;
import com.example.myproject.model.UserMoney;
import com.example.myproject.service.TorrentService;

import com.example.myproject.service.UserMoneyService;
import com.example.myproject.service.UserService;
import com.example.myproject.tracker.TrackerConfig;
import com.example.myproject.tracker.TrackerManager;
import com.example.myproject.ttorrent.common.src.main.java.com.turn.ttorrent.common.TorrentCreator;

import com.turn.ttorrent.bcodec.BDecoder;
import com.turn.ttorrent.bcodec.BEValue;
import com.turn.ttorrent.bcodec.BEncoder;
import com.turn.ttorrent.common.TorrentMetadata;
import com.turn.ttorrent.common.TorrentParser;
import com.turn.ttorrent.common.TorrentSerializer;

import com.dampcake.bencode.Bencode;
import com.dampcake.bencode.Type;

import lombok.AllArgsConstructor;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.EntityNotFoundException;
import java.io.*;
import java.net.InetAddress;
import java.net.URI;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

import java.time.LocalDateTime;
import java.util.stream.Collectors;
import java.util.Map;

import com.example.myproject.model.Tag;
import com.example.myproject.mapper.TagMapper;
import com.example.myproject.model.DownloadRecord;
import com.example.myproject.mapper.DownloadRecordMapper;
@Service

public class TorrentServiceImpl implements TorrentService {

    private final UserMapper userMapper;

    private final CategoryMapper categoryMapper;

    private final DownloadRecordMapper recordMapper;

    private final TorrentMapper torrentMapper;

    private final TorrentTagMapper torrenttagMapper;

    private final TrackerManager trackerManager;

    private final UserService userService;

    // 在类中添加
    private final TagMapper tagMapper;

    private final UserMoneyService userMoneyService;

  //  private final DownloadRecordMapper downloadRecordMapper;





    public static void createTorrentFile(String outputPath,
                                         String sourcePath,
                                         List<String> announceUrls,
                                         int pieceLengthKB) throws Exception {
        File source = new File(sourcePath);
        if (!source.exists() || !source.canRead()) {
            throw new IllegalArgumentException("无法访问源文件/目录: " + source.getName());
        }

        // 将 announce URL 字符串转换为 URI 对象
        List<URI> announceURIs = new ArrayList<>();
        for (String url : announceUrls) {
            announceURIs.add(new URI(url));
        }

        // 创建 announceList（支持多层 tracker）
        List<List<URI>> announceList = new ArrayList<>();
        announceList.add(announceURIs);  // 所有 tracker 都作为第一级（Tier 1）

        // 设置创建者信息
        String creator = String.format("%s (ttorrent)", System.getProperty("user.name"));
        int pieceLengthBytes = pieceLengthKB * 1024;

        // 创建 TorrentMetadata 对象
        TorrentMetadata torrent;
        if (source.isDirectory()) {
            List<File> files = new ArrayList<>(FileUtils.listFiles(source, TrueFileFilter.TRUE, TrueFileFilter.TRUE));
            Collections.sort(files);  // 保证一致性
            torrent = TorrentCreator.create(source, files, announceURIs.get(0), announceList, creator, pieceLengthBytes);
        } else {
            torrent = TorrentCreator.create(source, null, announceURIs.get(0), announceList, creator, pieceLengthBytes);
        }

        // 序列化并写入 .torrent 文件
        try (OutputStream fos = new FileOutputStream(outputPath)) {
            fos.write(new TorrentSerializer().serialize(torrent));
        }

//       System.out.println("Info hash: " + torrent.getHexInfoHash());
         System.out.println("Torrent file created at: " + outputPath);
    }

    public long getTorrentFileSize(File torrentFile) throws Exception {
        Map<String, BEValue> torrent = BDecoder.bdecode(new FileInputStream(torrentFile)).getMap();
        Map<String, BEValue> info = torrent.get("info").getMap();

        if (info.containsKey("length")) {
            // 单文件
            return info.get("length").getLong();
        } else if (info.containsKey("files")) {
            // 多文件
            List<BEValue> files = info.get("files").getList();
            long total = 0;
            for (BEValue f : files) {
                total += f.getMap().get("length").getLong();
            }
            return total;
        } else {
            return 0;
        }
    }


    @Override
    public Long uploadFile(Long userId, String name, Long categoryId, String desc,
                              MultipartFile file, List<Long>  tags,
                              Double originPrice, Integer downloadLimit) {
        // 使用当前工作目录 + 相对路径
        String baseUploadPath = System.getProperty("user.dir") + "/files/";
        String baseTorrentPath = System.getProperty("user.dir") + "/torrents/";

        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || originalFilename.isEmpty()) {
            throw new IllegalArgumentException("上传文件名不能为空");
        }

        // 创建目录（如不存在）
        File uploadDir = new File(baseUploadPath);
        if (!uploadDir.exists()) {
            boolean created = uploadDir.mkdirs();
            System.out.println("上传目录创建：" + created);
        }

        String uploadedFilePath = baseUploadPath + originalFilename;
        System.out.println("保存路径：" + uploadedFilePath);

        File uploadedFile = new File(uploadedFilePath);
        System.out.println("绝对路径：" + uploadedFile.getAbsolutePath());

        try {
            file.transferTo(uploadedFile);
        } catch (IOException e) {
            throw new BusinessException("保存资源文件失败");
        }


        System.out.println("原始文件已保存到: " + uploadedFilePath);

        // 生成 .torrent 文件
        String torrentFilename = originalFilename + ".torrent";
        String torrentFilePath = baseTorrentPath + torrentFilename;
        try {
            String localIP = InetAddress.getLocalHost().getHostAddress();
            System.out.println("本机地址IP: " + localIP);
            List<String> announceUrls = List.of("http://" + localIP + ":6969/announce");
            createTorrentFile(torrentFilePath, uploadedFilePath, announceUrls, 64);
        } catch (Exception e) {
            throw new BusinessException("生成种子文件失败");
        }


        File torrentFile = new File(torrentFilePath);
        trackerManager.registerTorrent(torrentFile);
        System.out.println("种子已生成并注册: " + torrentFilePath);

        // 入库
        Torrent t = new Torrent();
        t.setTorrentName(name);
        t.setUploaderId(userId);
        t.setCategoryId(categoryId);
        t.setTorrentDescription(desc);
        t.setTorrentSize(uploadedFile.length());
        t.setUploadTime(LocalDateTime.now());
        t.setTorrentStatus("pending");
        t.setOriginPrice(originPrice);
        t.setDownloadCount(0);
        t.setDownloadLimit(downloadLimit);
        t.setScore(0.0);
        t.setTorrentPath(torrentFilePath);
        torrentMapper.insert(t);

        long torrentId= t.getTorrentId();
        for (Long tagId : tags) {
            torrenttagMapper.insert(torrentId, tagId);
        }

        //奖励积分
        userMoneyService.reward(userId, 0,0,originPrice);
        userMoneyService.reward(userId, 10,0,10);

        return torrentId;

    }


    @Override
    public Long uploadTorrent(Long userId, String name, Long categoryId, String desc,
                              MultipartFile file, List<Long>  tags,
                              Double originPrice, Integer downloadLimit) {// 使用当前工作目录 + 相对路径
        String baseTorrentPath = System.getProperty("user.dir") + "/torrents/";

        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || !originalFilename.endsWith(".torrent")) {
            throw new IllegalArgumentException("请上传合法的 .torrent 文件");
        }

// 创建 torrents 目录（如不存在）
        File torrentDir = new File(baseTorrentPath);
        if (!torrentDir.exists()) {
            boolean created = torrentDir.mkdirs();
            System.out.println("种子目录创建：" + created);
        }

        File torrentFile = new File(baseTorrentPath + originalFilename);
        System.out.println("保存种子路径：" + torrentFile.getAbsolutePath());

        try {
            file.transferTo(torrentFile);
        } catch (IOException e) {
            throw new BusinessException("保存 .torrent 文件失败");
        }

        try {
            TorrentMetadata meta = new TorrentParser().parseFromFile(torrentFile);
            String announce = meta.getAnnounce().toString();
            if (announce.contains("passkey=")) {
                throw new BusinessException("请上传不含 passkey 的种子");
            }
        } catch (Exception e) {
            throw new BusinessException("解析种子文件失败: " + e.getMessage());
        }

        trackerManager.registerTorrent(torrentFile);

        Torrent t = new Torrent();
        t.setTorrentName(name);
        t.setUploaderId(userId);
        t.setCategoryId(categoryId);
        t.setTorrentDescription(desc);
        //上传真实文件大小
        try {
            t.setTorrentSize(getTorrentFileSize(torrentFile));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        t.setUploadTime(LocalDateTime.now());
        t.setTorrentStatus("pending");
        t.setOriginPrice(originPrice);
        t.setDownloadCount(0);
        t.setDownloadLimit(downloadLimit);
        t.setScore(0.0);
        t.setTorrentPath(torrentFile.getAbsolutePath());
        torrentMapper.insert(t);

        long torrentId= t.getTorrentId();
        if (tags == null) {
            tags = new ArrayList<>();
        }

        for (Long tagId : tags) {
            torrenttagMapper.insert(torrentId, tagId);
        }
        userMoneyService.reward(userId, 0,0,originPrice);
        userMoneyService.reward(userId, 10,0,10);
        return torrentId;
    }

    /**
     * 创建一个新 .torrent 文件，将 announce URL 中添加 passkey 参数
     * @param outputPath       输出文件路径
     * @param baseTorrentFile  原始模板 .torrent 文件
     * @param passkey          用户的唯一 passkey
     * @throws IOException     任何 I/O 或解析异常
     */
    public static void createTorrentFileForUser(String outputPath, File baseTorrentFile, String passkey) throws IOException {
        try {
            // 1. 读取原始 .torrent 文件内容为 byte[]
            byte[] fileBytes = FileUtils.readFileToByteArray(baseTorrentFile);

            // 2. 解析为 Map<String, BEValue>
            Map<String, BEValue> metadata = BDecoder.bdecode(new ByteArrayInputStream(fileBytes)).getMap();

            // 3. 获取原始 announce 字段（可能为空）
            BEValue announceValue = metadata.get("announce");
            String oldAnnounce = announceValue == null ? "" : announceValue.getString();

            // 4. 添加 passkey 到 announce URL（简单添加 ? 或 &）
            String newAnnounce = addPasskeyToAnnounce(oldAnnounce, passkey);
            metadata.put("announce", new BEValue(newAnnounce));

            // 5. 删除 announce-list（否则客户端可能优先用旧的 tracker）
            metadata.remove("announce-list");

            // 6. 编码为 .torrent 文件内容
            byte[] newTorrentBytes = BEncoder.bencode(metadata).array();

            // 7. 写入新文件
            FileUtils.writeByteArrayToFile(new File(outputPath), newTorrentBytes);

        } catch (Exception e) {
            throw new IOException("创建带 passkey 的 .torrent 文件失败", e);
        }
    }

    /**
     * URL 后添加 passkey 参数
     */
    private static String addPasskeyToAnnounce(String oldUrl, String passkey) {
        if (oldUrl == null || oldUrl.isEmpty()) {
            // 默认 tracker 地址
            String localIP = null;
            try {
                localIP = InetAddress.getLocalHost().getHostAddress();
            } catch (UnknownHostException e) {
                throw new RuntimeException(e);
            }
            oldUrl = "http://" + localIP + ":6969/announce";
        }
        String delimiter = oldUrl.contains("?") ? "&" : "?";
        return oldUrl + delimiter + "passkey=" + passkey;
    }


    private String appendPasskeyToUrl(String url, String passkey) {
        if (url.contains("?")) {
            return url + "&passkey=" + passkey;
        } else {
            return url + "?passkey=" + passkey;
        }
    }

    private String generateMagnetLink(File torrentFile, String passkey) throws IOException, NoSuchAlgorithmException {
        // 1. 解析 .torrent
        byte[] fileBytes = FileUtils.readFileToByteArray(torrentFile);
        Map<String, BEValue> metadata = BDecoder.bdecode(new ByteArrayInputStream(fileBytes)).getMap();

        // 2. 取 info 字典
        BEValue infoValue = metadata.get("info");
        byte[] infoBytes = BEncoder.bencode(infoValue.getMap()).array();

        // 3. 计算 SHA-1 (infohash)
        MessageDigest sha1 = null;
        try {
            sha1 = MessageDigest.getInstance("SHA-1");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
        byte[] infoHash = sha1.digest(infoBytes);
        String infoHashHex = bytesToHex(infoHash);

        // 4. 获取 name
        String name = infoValue.getMap().get("name").getString();
        String encodedName = URLEncoder.encode(name, StandardCharsets.UTF_8);

        // 5. 构造 tracker url（带 passkey）
        String localIP = InetAddress.getLocalHost().getHostAddress();
        String trackerUrl = "http://" + localIP + ":6969/announce?passkey=" + passkey;
        String encodedTracker = URLEncoder.encode(trackerUrl, StandardCharsets.UTF_8);

        // 6. 拼接磁力链接
        return "magnet:?xt=urn:btih:" + infoHashHex + "&dn=" + encodedName + "&tr=" + encodedTracker;
    }

    // 将 byte[] 转为十六进制字符串
    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

    @Override
    public DownloadUrlDTO initiateDownload(Long torrentId, Long userId) {
        Torrent t = torrentMapper.selectById(torrentId);
        if (t == null) {
            throw new BusinessException("资源不存在");
        }

        File baseTorrentFile = new File(t.getTorrentPath());
        if (!baseTorrentFile.exists()) {
            throw new BusinessException("模板种子不存在");
        }

        //给扣除下载的钱，给上传者奖钱
        if (t.getOriginPrice()<userMoneyService.getMagicValue(userId)){
            userMoneyService.reward( userId,0,0,0-t.getOriginPrice());
            userMoneyService.reward( t.getUploaderId(),0,0,t.getOriginPrice());
        }else {
            throw new BusinessException("魔力值不够支付种子");
        }
        String passkey = userService.getPasskeyByUserId(userId);
//        String newAnnounceUrl = "http://127.0.0.1:6969/announce?passkey=" + passkey;

        String customFileName = torrentId + "_" + userId + ".torrent";

        // 生成用户专属种子
// 使用项目当前目录 + 相对路径
        String torrentDirPath = System.getProperty("user.dir") + "/torrent/";
        String fullCustomPath = torrentDirPath + customFileName;

// 创建 torrent 目录（如不存在）
        File torrentDir = new File(torrentDirPath);
        if (!torrentDir.exists()) {
            boolean created = torrentDir.mkdirs();
            System.out.println("torrent目录创建：" + created);
        }

// 生成用户专属种子
        try {
            createTorrentFileForUser(fullCustomPath, baseTorrentFile, passkey);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

// 监听并注册
        File torrentFile = new File(fullCustomPath);
        trackerManager.registerTorrent(torrentFile);

// 生成磁力链接
        String magnetLink = null;
        try {
            magnetLink = generateMagnetLink(torrentFile, passkey);
        } catch (IOException | NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }

        System.out.println("磁力链接: " + magnetLink);

        // 下载记录
        Torrent torrent=torrentMapper.selectById(torrentId);
        DownloadRecord record = new DownloadRecord();
        record.setUserId(userId);
        record.setTorrentId(torrentId);
        record.setDownloadByte(torrent.getTorrentSize());
        record.setIsComplete(false);
        recordMapper.insert(record);

        DownloadUrlDTO dto = new DownloadUrlDTO();
        dto.setDownloadUrl("http://localhost:8080/torrent/" + customFileName);
        dto.setRecordId(record.getRecordId());
        dto.setMagnetUrl(magnetLink);
        return dto;
    }


    @Override
    public void completeDownload(Long torrentId, DownloadNotifyDTO dto, Long userId) {
        DownloadRecord record = recordMapper.selectById(dto.getRecordId().toString());
        if (record == null || !record.getUserId().equals(userId)) {
            throw new BusinessException("下载记录不存在或无权限");
        }

        if (Boolean.TRUE.equals(dto.getIsComplete())) {
            record.setIsComplete(true);
            recordMapper.updateById(record);

            Torrent t = torrentMapper.selectById(torrentId);
            t.setDownloadCount(t.getDownloadCount() + 1);
            torrentMapper.updateById(t);
        }
    }


    @Override
    public PagedResult<TorrentVO> search(SearchTorrentsDTO params) {
        // 分页查询关键字
        Page<Torrent> pageReq = new Page<>(params.getPage(), params.getSize());
        QueryWrapper<Torrent> qw = new QueryWrapper<>();
//        qw.eq("torrent_status", "normal");
        if (params.getKeyword() != null && !params.getKeyword().isEmpty()) {
            // select * from Torrent where torrent_name like "%keyword%"
            qw.like("torrent_name", params.getKeyword())
                    .or().like("torrent_description", params.getKeyword());
        }
        Page<Torrent> pageRes = torrentMapper.selectPage(pageReq, qw);
        // 转换实体到VO
        List<TorrentVO> voList = pageRes.getRecords().stream().map(entity -> {
            TorrentVO vo = new TorrentVO();
            BeanUtils.copyProperties(entity, vo);
            return vo;
        }).collect(Collectors.toList());
        return new PagedResult<>(voList, pageRes.getTotal(), pageRes.getCurrent(), pageRes.getSize());
    }

    @Override
    public List<TorrentVO> byTag(String tagName) {
//        List<String> tagNames = Collections.singletonList(tagName.trim());
//        // ★ 传入 tagNames 以及 tagNames.size()
//        List<Long> torrentIds = torrenttagMapper.findTorrentIdsByTagNames(tagNames, tagNames.size());
//        if (torrentIds.isEmpty()) {
//            return Collections.emptyList();
//        }
//        List<Torrent> torrents = baseMapper.selectBatchIds(torrentIds);
//        return torrents.stream().map(this::toVO).collect(Collectors.toList());
        return null;
    }

    @Override
    public List<TorrentVO> byCategory(Integer categoryId) {
        QueryWrapper<Torrent> qw = new QueryWrapper<>();
        qw.eq("category_id", categoryId);
           //     .eq("torrent_status", "normal");
        List<Torrent> list = torrentMapper.selectList(qw);
        return list.stream().map(entity -> {
            TorrentVO vo = new TorrentVO();
            BeanUtils.copyProperties(entity, vo);
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    public List<TorrentVO> sortByUploadTime(String order, Integer page, Integer size) {
        Page<Torrent> pg = new Page<>(page, size);
        QueryWrapper<Torrent> qw = new QueryWrapper<>();
        if ("asc".equalsIgnoreCase(order)) {
            qw.orderByAsc("upload_time");
        } else {
            qw.orderByDesc("upload_time");
        }
        Page<Torrent> res = torrentMapper.selectPage(pg, qw);
        return res.getRecords().stream().map(entity -> {
            TorrentVO vo = new TorrentVO();
            BeanUtils.copyProperties(entity, vo);
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    public List<TorrentVO> sortByDownloads(String order, Integer page, Integer size) {
        Page<Torrent> pg = new Page<>(page, size);
        QueryWrapper<Torrent> qw = new QueryWrapper<>();
        qw.eq("torrent_status", "normal");
        if ("asc".equalsIgnoreCase(order)) {
            qw.orderByAsc("download_count");
        } else {
            qw.orderByDesc("download_count");
        }
        Page<Torrent> res = torrentMapper.selectPage(pg, qw);
        return res.getRecords().stream().map(entity -> {
            TorrentVO vo = new TorrentVO();
            BeanUtils.copyProperties(entity, vo);
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    public TorrentDetailDTO getTorrentDetail(Long torrentId) {
        Torrent t = torrentMapper.selectById(torrentId);
        if (t == null) {
            throw new EntityNotFoundException("种子不存在");
        }

        // 取category名称
        String categoryName = categoryMapper.selectNameById(t.getCategoryId());

        // 取uploader名称
        String uploaderName = userMapper.selectUserNameById(t.getUploaderId());

        // 取标签id列表
        List<Long> tagIds = torrenttagMapper.selectTagIdsByTorrentId(torrentId);

        // 取标签名列表
        List<String> tagNames = torrenttagMapper.selectTagNamesByTorrentId(torrentId);

        // DTO封装
        TorrentDetailDTO dto = new TorrentDetailDTO();
        BeanUtils.copyProperties(t, dto);
        // 将分数保留两位小数
        if (dto.getScore() != null) {
            dto.setScore(Math.round(dto.getScore() * 100.0) / 100.0);
        }
        dto.setCategoryName(categoryName);
        dto.setUploaderName(uploaderName);

        dto.setTags(tagIds);
        dto.setTagNames(tagNames);

        return dto;
    }




    // 构造器注入中加上 TagMapper
    public TorrentServiceImpl(
            UserMapper userMapper,
            CategoryMapper categoryMapper,
            DownloadRecordMapper recordMapper,
            TorrentMapper torrentMapper,
            TorrentTagMapper torrenttagMapper,
            TrackerManager trackerManager,
            UserService userService,
            TagMapper tagMapper, UserMoneyMapper userMoneyMapper, UserMoneyService userMoneyService // 新增

    ) {
        this.userMapper = userMapper;
        this.categoryMapper = categoryMapper;
        this.recordMapper = recordMapper;
        this.torrentMapper = torrentMapper;
        this.torrenttagMapper = torrenttagMapper;
        this.trackerManager = trackerManager;
        this.userService = userService;
        this.tagMapper = tagMapper;
        this.userMoneyService = userMoneyService;
    }

    // 新增方法
    @Override
    public List<Tag> getAllTags() {
        return tagMapper.selectList(null);
    }
    @Override
    public List<DownloadRecordDTO> getDownloadRecordsByUserId(Long userId) {
        List<DownloadRecord> records = recordMapper.selectList(
                new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<DownloadRecord>()
                        .eq("user_id", userId)
        );
        List<DownloadRecordDTO> result = new ArrayList<>();
        for (DownloadRecord record : records) {
            DownloadRecordDTO dto = new DownloadRecordDTO();
            dto.setRecordId(record.getRecordId());
            dto.setTorrentId(record.getTorrentId().longValue());

            dto.setDownloadByte(record.getDownloadByte());
            Torrent torrent = torrentMapper.selectById(record.getTorrentId());
            dto.setTorrentName(torrent != null ? torrent.getTorrentName() : null);
            dto.setDownloadTime(record.getDownloadTime() != null ? record.getDownloadTime().toString() : null);
            result.add(dto);
        }
        return result;
    }

    
    @Override
    public PagedResult<TorrentVO> filterByCategoryAndTags(FilterTorrentsDTO params) {

        // ----------0. 参数校验 ----------
        if (params.getTags() == null || params.getTags().isEmpty()) {
            // 标签不能为空
            return emptyPage(params.getPage(), params.getSize());
        }

        // ----------1. tagName -> tagId ----------
        List<Long> tagIds = new ArrayList<>();
        for (String tagName : params.getTags()) {
            Tag tag = tagMapper.selectOne(
                    new QueryWrapper<Tag>().eq("tag_name", tagName.trim()));
            if (tag != null) {
                tagIds.add(tag.getTagId());
            }
        }
        if (tagIds.isEmpty()) {                 // 输入的标签数据库里都不存在
            return emptyPage(params.getPage(), params.getSize());
        }

        // ----------2. 找到同时包含这些 tag 的 torrentId ----------
        List<Long> torrentIds =
                torrenttagMapper.findTorrentIdsByTags(tagIds, tagIds.size());
        if (torrentIds == null || torrentIds.isEmpty()) {
            return emptyPage(params.getPage(), params.getSize());
        }

        // ----------3. 分页查 torrent ----------
        Page<Torrent> pageReq = new Page<>(params.getPage(), params.getSize());
        QueryWrapper<Torrent> qw = new QueryWrapper<>();
        qw.in("torrent_id", torrentIds);
        if (params.getCategoryId() != null) {   // 分类可选
            qw.eq("category_id", params.getCategoryId());
        }

        Page<Torrent> pageRes = torrentMapper.selectPage(pageReq, qw);

        // ----------4. 封装为 VO ----------
        List<TorrentVO> voList = pageRes.getRecords()
                .stream()
                .map(this::toVO)
                .collect(Collectors.toList());

        return new PagedResult<>(voList,
                pageRes.getTotal(),
                pageRes.getCurrent(),
                pageRes.getSize());
    }


    /** 返回空分页结果 */
    private PagedResult<TorrentVO> emptyPage(long page, long size) {
        return new PagedResult<>(Collections.emptyList(), 0L, page, size);
    }

    /** Torrent -> TorrentVO 简易映射 */
    private TorrentVO toVO(Torrent t) {
        TorrentVO vo = new TorrentVO();
        vo.setTorrentId(t.getTorrentId());
        vo.setTorrentName(t.getTorrentName());
        vo.setTorrentDescription(t.getTorrentDescription());
        vo.setTorrentSize(t.getTorrentSize());
        vo.setUploadTime(t.getUploadTime());
        vo.setDownloadCount(t.getDownloadCount());
        vo.setStatus(t.getTorrentStatus());
        vo.setOriginPrice(t.getOriginPrice());

        // Integer 转 String
        if (t.getDownloadLimit() != null) {
            vo.setDownloadLimit(String.valueOf(t.getDownloadLimit()));
        } else {
            vo.setDownloadLimit("无限制"); // 或者你想显示的默认值
        }
        return vo;
    }
}
